/*
  Copyright 2006 by Sean Luke and George Mason University
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/

package sim.util.gui;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.text.*;

/**
   HTMLBrowser is a simple web browser which lets the user click on links and which provides
   a Back button when appropriate.  That's it!
*/

public class HTMLBrowser extends JPanel
    {
    java.util.Stack stack = new java.util.Stack();
    JEditorPane infoPane;
    JScrollPane scroll;
        
    public void setText(Object HTMLTextOrURL)
        {
        if (HTMLTextOrURL == null) HTMLTextOrURL = "<html><body bgcolor='white'></body></html>";
        stack = new java.util.Stack();
        // delete any notion of a URL.  What a pain -- this is so backwards!
        // This is because JEditorPane's setText doesn't eliminate the
        // stream description property of the text (a bug), so the system
        // still thinks the URL is valid.
        infoPane.setContentType("text/html");
        Document d = infoPane.getEditorKit().createDefaultDocument();
        //if (d instanceof AbstractDocument)
        //      {
        //      ((AbstractDocument)d).setAsynchronousLoadPriority(1);
        //      }
        infoPane.setDocument(d);
        if (HTMLTextOrURL instanceof String)
            infoPane.setText((String)HTMLTextOrURL);
        else if (HTMLTextOrURL instanceof URL)
            try
                {
                infoPane.setPage((URL)HTMLTextOrURL);
                }
            catch (IOException e) 
                { 
                e.printStackTrace(); 
                infoPane = new JEditorPane(); 
                }
        else
            {
            new RuntimeException("Info object was neither a string nor a URL").printStackTrace();
            infoPane = new JEditorPane();
            }

        // override a bug in JEditorPane which scrolls to the bottom on all subsequent Consoles
        infoPane.getCaret().setDot(0);
        }
                
                
                
    /** Constructs an HTMLBrowser using either an HTML string or a URL */
    public HTMLBrowser(final Object HTMLTextOrURL)
        {
        infoPane = new JEditorPane();
        setText(HTMLTextOrURL);
                
        infoPane.setEditable(false);
        scroll = new JScrollPane(infoPane);        
        setLayout(new BorderLayout());
        add(scroll,BorderLayout.CENTER);
        // override a bug in JEditorPane which scrolls to the bottom on all subsequent Consoles
        infoPane.getCaret().setDot(0);

        // add a back button and 
        JButton backButton = new JButton("Back");
        final Box backButtonBox = new Box(BoxLayout.X_AXIS);
        backButtonBox.add(backButton);
        backButtonBox.add(Box.createGlue());

        // make the hyperlinks active
        infoPane.addHyperlinkListener(new HyperlinkListener()
            {
            public void hyperlinkUpdate( HyperlinkEvent he ) 
                {
                HyperlinkEvent.EventType type = he.getEventType();
                if (type == HyperlinkEvent.EventType.ENTERED) 
                    {
                    infoPane.setCursor(Cursor.getPredefinedCursor( Cursor.HAND_CURSOR) );
                    } 
                else if (type == HyperlinkEvent.EventType.EXITED) 
                    {
                    infoPane.setCursor( Cursor.getDefaultCursor() );
                    } 
                else // clicked on it!
                    {
                    java.net.URL url = he.getURL();
                    try
                        {
                        infoPane.getEditorKit().createDefaultDocument();
                        infoPane.setPage(url);
                        if (stack.isEmpty())
                            {
                            // show back button
                            add(backButtonBox,BorderLayout.SOUTH);
                            revalidate();
                            }
                        stack.push(url);
                        }
                    catch (Exception e)
                        {
                        e.printStackTrace();
                        java.awt.Toolkit.getDefaultToolkit().beep();
                        }
                    }
                }
            });

        // code for when the user presses the "Back" button
        backButton.addActionListener(new ActionListener()
            {
            public void actionPerformed(ActionEvent ae)
                {
                try
                    {
                    stack.pop();
                    if (stack.isEmpty())
                        {
                        // hide back button
                        remove(backButtonBox);
                        revalidate();
                        setText(HTMLTextOrURL);
                        }
                    else infoPane.setPage((java.net.URL)(stack.peek()));
                    }
                catch (Exception e)
                    {
                    System.err.println("This should not have happened.");
                    e.printStackTrace();
                    /* should never happen */
                    }
                }
            });
        }
    }
